#include <iostream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <thread>
#include <pthread.h>


// 线程局部存储
// 编译型关键字，给每个线程来一份
// 虽然用的是同一份值和变量名，但是编译的时候把它地址编程不同
// 此时就叫做线程局部存储
// 注意：__thread 只能修饰内置类型
__thread int shared_value = 100; // 此时主线程和新线程看到的地址不同


// 把地址转化为 16 进制
std::string toHex(pthread_t tid){
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%lx", tid);
    return buffer;
}


void *start(void *args)
{
    std::string name = static_cast<const char*>(args);
    sleep(1);
    while(true)
    {
        // std::cout << "I am a new thread, name: " << name << ", thread is: " << toHex(pthread_self()) << std::endl;
        printf("I am a new thread, name: %s, shared_value: %d, &shared_value: %p\n", name.c_str(), shared_value, &shared_value);
        sleep(1);
    }
    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start, (void*)"thread-1");
    std::cout << "I am a new thread, name: main " << toHex(pthread_self()) 
        << ", New thread id: " << toHex(tid)  << std::endl;

    while(true)
    {
        printf("main thread, shared_value: %d, &shared_value: %p\n", shared_value, &shared_value);

        shared_value += 10;
        sleep(1);
    }

    pthread_join(tid, nullptr);
    return 0;
}



// void *start(void *args)
// {
//     // // 可以的
//     // pid_t id = fork();
//     // if(id == 0)
//     // {
//     // }

//     // pthread_detach(pthread_self()); // 把当前线程分离
//     std::string name = static_cast<const char*>(args);
//     while(true){
//         std::cout << "I am a new thread" << std::endl;
//         sleep(1);
//         // break;
//     }
//     // return 0; // 10. 新线程 return 表示该线程退出
//     // exit(1); // 任何地方内部调用 exit，表示进程退出！！ 尽管是在线程内部
//     // pthread_exit((void*)10); // 第二种退出方法，和 return 等价
// }


// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, start, (void*)"thread-1");
//     //pthread_detach(tid); // 对指定线程做分离

//     sleep(3);
    
//     //pthread_cancel(tid); // 第三种退出方式
//     //std::cout << "取消线程: " << tid << std::endl;
   
//     //sleep(3);

//     void *ret = nullptr;
//     // 一个线程被取消之后，ret = -1，线程的退出码是 PTHREAD_CANCELD
//     int n = pthread_join(tid, &ret);
//     std::cout << "new thread exit code: " << (long long int)ret << ", n: " << n << std::endl;

//     return 0; // 10. 主线程return： 表示进程结束
// }



// int *addr = nullptr;

// void *start1(void *args)
// {
//     std::string name = static_cast<const char*>(args);
//     int a = 100;
//     addr = &a;
//     while(true){
//         std::cout << name << " local val a: " << a << std::endl;
//         sleep(1);
//     }
// }

// void *start2(void *args)
// {
//     std::string name = static_cast<const char*>(args);
//     while(true){
//         if(addr != nullptr)
//             std::cout << name << " mod val a: " << (*addr)++ << std::endl;
//         sleep(1);
//     }
// }

// int main()
// {
//     // 不同线程通过地址可以访问其他线程的栈
//     pthread_t tid1, tid2;
//     pthread_create(&tid1, nullptr, start1, (void*)"thread-1");
//     pthread_create(&tid2, nullptr, start2, (void*)"thread-2");

//     pthread_join(tid1, nullptr);
//     pthread_join(tid2, nullptr);

//     return 0;
// }





// class ThreadData
// {
// public:
//     ThreadData()
//     {}
//     void Init(const std::string &name, int a, int b){
//         _name = name;
//         _a = a;
//         _b = b;
//     }
    
//     void Excute(){_result =  _a + _b;}

//     int Result(){return _result;}

//     std::string Name(){return _name;}
//     void SetId(pthread_t tid) {_tid = tid;}
//     pthread_t Id() {return _tid;}
//     int A() {return _a;}
//     int B() {return _b;}
//     ~ThreadData()
//     {}

// private:
//     std::string _name;
//     int _a, _b;
//     int _result; // 返回结果
//     pthread_t _tid;
// };

// int gval = 100;

// std::string toHex(pthread_t tid){
//     char buffer[64];
//     snprintf(buffer, sizeof(buffer), "0x%lx", tid);
//     return buffer;
// }

// void *routine(void *args){
//     ThreadData *td = static_cast<ThreadData *> (args);
//     while(true){
//         std::cout << "我是新线程, 我的名字是" << td->Name() << ", my tid is : " << toHex(pthread_self()) << ", 全局变量(会修改): " << gval << std::endl;
//         gval++;
//         td->Excute();
//         sleep(1);
//         break; // 结束当前线程死循环
//     }
//     return td;
// }


// // 现在有一批数据，每一个数据的结果都让线程进行运算并且进行汇总
// #define NUM 10
// int main()
// {
//     ThreadData td[NUM];
//     // 1. 准备好我们要价格处理的数据
//     for(int i = 0; i < NUM; i++){
//         char id[64];
//         snprintf(id, sizeof(id), "thread-%d", i);
//         td[i].Init(id, i * 10, i * 20);
//     }

//     // 2. 创建多线程
//     for(int i = 0; i < NUM; i++){
//         pthread_t id;
//         pthread_create(&id, nullptr, routine, &td[i]);
//         td[i].SetId(id);
//     }

//     // 3. 等待多个线程
//     for(int i = 0; i < NUM; i++)
//     {
//         pthread_join(td[i].Id(), nullptr);
//     }

//     // 4. 汇总处理结果
//     for(int i = 0; i < NUM; i++)
//     {
//         printf("td[%d]: %d + %d = %d[%ld]\n", i, td[i].A(), td[i].B(), td[i].Result(), td[i].Id());
//     }

//     // 5. 在线程内部先变成有序的，然后在汇总时候进行归并式的排序

//     return 0;
// }




// class ThreadData
// {
// public:
//     ThreadData(const std::string &name, int a, int b): _name(name), _a(a), _b(b)
//     {}
//     void Excute(){_result =  _a + _b;}

//     int Result(){return _result;}

//     std::string Name(){return _name;}
//     ~ThreadData()
//     {}

// private:
//     std::string _name;
//     int _a, _b;

//     int _result; // 返回结果
// };

// // 5. 全局变量在线程内都是共享的
// int gval = 100;

// // 在多线程代码中，想要多个线程看到同一份资源只需要用全局变量就可以了
// // std::queue<int> q;
// // char buffer[4096];

// std::string toHex(pthread_t tid){
//     // 4. 进程内的函数，线程共享
//     char buffer[64];
//     snprintf(buffer, sizeof(buffer), "0x%lx", tid);
//     return buffer;
// }


// void *routine(void *args){
//     ThreadData *td = static_cast<ThreadData *> (args);
//     while(true){
//         std::cout << "我是新线程, 我的名字是" << td->Name() 
//         << ", my tid is : " << toHex(pthread_self()) 
//         << ", 全局变量(会修改): " << gval << std::endl;
//         gval++;
        
//         //std::cout << "task result is : " << td->Excute() << std::endl;
//         td->Excute();

//         sleep(1);
//         break; // 结束当前线程死循环
//     }
//     // 9. 返回值问题：返回参数，可以是变量、数字、对象
//     // return (void*)10;  // 线程退出方式1 : 线程入口函数return，表示线程退出
//     // 9.1：理论上，堆空间也是共享的，但是我们认为堆空间属于每个线程独占的
//     //      原因：因为谁拿着堆空间的入口地址，谁就能访问该堆区
//     // int *p = new int(10);
//     // return (void*)p; // 返回堆指针

//     return td;
// }



// int main()
// {
//     pthread_t tid;
//     // 8. 传参问题：传递参数，可以是变量、数字、对象
//     // 意味着其实一次可以给线程传递多个参数
//     ThreadData *td = new ThreadData("thread-1", 10, 20);
//     pthread_create(&tid, nullptr, routine, td);

//     // 7. 线程创建之后，也是需要被等待和回收的
//     // 7.1 理由：
//     //      a. 类似于僵尸进程的问题
//     //      b. 为了知道新线程的执行结果

//     // 9. 返回值问题
//     // void *ret = nullptr;
//     ThreadData *rtd = nullptr;

// //    int n = pthread_join(tid, nullptr);
//     int n = pthread_join(tid, (void**)&rtd); // 我们可以保证执行完毕，任务一定处理完了，结果变量一定已经被写入了

//     if(n != 0){
//         std::cerr << "join error: " << n  << ", " << strerror(n) << std::endl;
//         return 1;
//     }
    
//     // std::cout << "join success! ret: " << (long long int) ret <<std::endl; // 等待新线程退出后，结束等待
//     std::cout << "join success! ret: " << rtd->Result() <<std::endl; 
   
//     return 0;
// }





// // 5. 全局变量在线程内都是共享的
// int gval = 100;

// // 多个线程执行一个函数：routine 被重入了
// // 一切皆文件：向显示器打印就是向文件写入，所以显示器文件就相当于被线程共享的公共资源
// void *routine1(void *args){
//     std::string name = static_cast<const char*>(args);
//     while(true){
//         // 3. 不加保护的情况下，显示器文件就是共享资源
//         std::cout << "我是新线程, 我的名字是" << name 
//         << ", my tid is : " << toHex(pthread_self()) 
//         << ", 全局变量(会修改): " << gval << std::endl;
//         gval++;
//         sleep(1);
//     }
//     return 0;
// }


// void *routine2 (void *args){
//     std::string name = static_cast<const char*>(args);
//     while(true){
//         // 3. 不加保护的情况下，显示器文件就是共享资源
//         std::cout << "我是新线程, 我的名字是" << name 
//         << ", my tid is : " << toHex(pthread_self()) 
//         << ", 全局变量(只是检测): " << gval << std::endl;
//         sleep(1);
//         // 6. 线程一旦出现异常，可能会导致其他线程全部崩溃
//         // 6.1 异常的本质： 信号
//         int *p = nullptr;
//         *p = 100;
//     }
//     return 0;
// }

// int main(){
//     // 1. 新线程 和 main 线程谁先运行 -> 不确定
//     // 2. 线程创建出来，要对进程的时间片进行瓜分

//     pthread_t tid;
//     pthread_create(&tid, nullptr, routine1, (void*)"thread-1");

//     pthread_t tid2;
//     pthread_create(&tid2, nullptr, routine2, (void*)"thread-2");


//     printf("new thread id: 0x0%lx\n", tid);
//     printf("new thread id: 0x0%lx\n", tid2);


//     while(true){
//         std::cout << "我是 main线程..." << std::endl;
//         sleep(1);
//     }
//     return 0;
// }
